package org.melanesia.sql;

import java.sql.Connection;
import java.sql.SQLException;

import org.melanesia.converters.TypeConverter;
import org.melanesia.sql.exceptions.SQLExecutionException;
import org.melanesia.sql.utils.JDBCUtils;

/**
 * This class is an entry point into the Melanesia framework. It gives access to
 * framework functionality such as creating SQL Queries, Stored Procedure Calls
 * or Batches.
 *
 * @author marcin.kielar
 */
public final class SQLBuilder {

    /**
     * Instance of database connection.
     */
    private final Connection connection;

    /**
     * Instance of type converter.
     */
    private final TypeConverter typeConverter;

    /**
     * Constructs SQLBuilder with default type converter.
     *
     * @param connection
     *            a JDBC connection object
     */
    public SQLBuilder(final Connection connection) {
        this(connection, null);
    }

    /**
     * Constructs SQLBuilder with specified type converter.
     *
     * @param connection
     *            a JDBC connection object
     * @param typeConverter
     *            data type converter
     *
     * @see TypeConverter
     */
    public SQLBuilder(final Connection connection, final TypeConverter typeConverter) {
        this.connection = connection;
        this.typeConverter = typeConverter != null ? typeConverter : new TypeConverter();

        try {
            connection.setAutoCommit(false);
        } catch (SQLException ex) {
            throw new SQLExecutionException(ex);
        }
    }

    /**
     * Returns this builder's type converter.
     *
     * @return type converter
     *
     * @see TypeConverter
     */
    public TypeConverter getTypeConverter() {
        return typeConverter;
    }

    /**
     * Factory method for creating database queries.
     *
     * @param sql
     *            SQL query string
     * @return query object for further parameterization
     *
     * @see Query
     */
    public Query createQuery(final String sql) {
        return new Query(connection, typeConverter, sql);
    }

    /**
     * Factory method for creating database calls. (stored procedures, etc.)
     *
     * @param sql
     *            SQL call string
     * @return call object for further parameterization
     *
     * @see Call
     */
    public Call createCall(final String sql) {
        return new Call(connection, typeConverter, sql);
    }

    /**
     * Factory method for creating batches of database queries (usually used for
     * multiple insert/update statements).
     *
     * @param sql
     *            SQL query string
     * @return batch object for further parameterization
     *
     * @see Batch
     * @since 0.0.2
     */
    public Batch createBatch(final String sql) {
        return new Batch(connection, typeConverter, sql);
    }

    /**
     * Commits transaction.
     */
    public void commit() {
        try {
            connection.commit();
        } catch (SQLException ex) {
            throw new SQLExecutionException(ex);
        }
    }

    /**
     * Rolls back transaction.
     */
    public void rollback() {
        try {
            connection.rollback();
        } catch (SQLException ex) {
            throw new SQLExecutionException(ex);
        }
    }

    /**
     * Closes associated JDBC connection and makes this SQLBuilder unusable.
     */
    public void closeConnection() {
        JDBCUtils.close(connection);
    }

    /**
     * Returns jdbc connection used by this <code>SQLBuilder</code>. This method
     * should be used with caution, as manipulating the connection state can
     * cause disastrous consequences for SQLBuilder.
     *
     * Usually connection access is required for creation some of the non-basic
     * jdbc typed, for example implementations of {@link java.sql.Array}.
     *
     * @return jdbc connection
     */
    public Connection getJdbcConnection() {
        return connection;
    }
}
